#include "StdAfx.h"
#include "ModPlayer.h"

#include "../sys/File.h"

CModPlayer CModPlayer::__this;
u8 CModPlayer::m_channelPan[8] = { 0, 127, 127, 0, 0, 127, 127, 0};



u16 amiga_table[16][36] =
{
//	C   C#  D   D#  E   F   F#  G   G#  A   A#  B
// Tuning 0, Normal
{
	856,808,762,720,678,640,604,570,538,508,480,453,	//octave 1
	428,404,381,360,339,320,302,285,269,254,240,226,	//octave 2
	214,202,190,180,170,160,151,143,135,127,120,113		//octave 3
},
// Tuning 1
{
	850,802,757,715,674,637,601,567,535,505,477,450,
	425,401,379,357,337,318,300,284,268,253,239,225,
	213,201,189,179,169,159,150,142,134,126,119,113
},
// Tuning 2
{
	844,796,752,709,670,632,597,563,532,502,474,447,
	422,398,376,355,335,316,298,282,266,251,237,224,
	211,199,188,177,167,158,149,141,133,125,118,112
},
// Tuning 3
{
	838,791,746,704,665,628,592,559,528,498,470,444,
	419,395,373,352,332,314,296,280,264,249,235,222,
	209,198,187,176,166,157,148,140,132,125,118,111
},
// Tuning 4
{
	832,785,741,699,660,623,588,555,524,495,467,441,
	416,392,370,350,330,312,294,278,262,247,233,220,
	208,196,185,175,165,156,147,139,131,124,117,110
},
// Tuning 5
{
	826,779,736,694,655,619,584,551,520,491,463,437,
	413,390,368,347,328,309,292,276,260,245,232,219,
	206,195,184,174,164,155,146,138,130,123,116,109
},
// Tuning 6
{
	820,774,730,689,651,614,580,547,516,487,460,434,
	410,387,365,345,325,307,290,274,258,244,230,217,
	205,193,183,172,163,154,145,137,129,122,115,109
},
// Tuning 7
{
	814,768,725,684,646,610,575,543,513,484,457,431,
	407,384,363,342,323,305,288,272,256,242,228,216,
	204,192,181,171,161,152,144,136,128,121,114,108
},
// Tuning -8
{
	907,856,808,762,720,678,640,604,570,538,508,480,
	453,428,404,381,360,339,320,302,285,269,254,240,
	226,214,202,190,180,170,160,151,143,135,127,120
},
// Tuning -7
{
	900,850,802,757,715,675,636,601,567,535,505,477,
	450,425,401,379,357,337,318,300,284,268,253,238,
	225,212,200,189,179,169,159,150,142,134,126,119
},
// Tuning -6
{
	894,844,796,752,709,670,632,597,563,532,502,474,
	447,422,398,376,355,335,316,298,282,266,251,237,
	223,211,199,188,177,167,158,149,141,133,125,118
},
// Tuning -5
{
	887,838,791,746,704,665,628,592,559,528,498,470,
	444,419,395,373,352,332,314,296,280,264,249,235,
	222,209,198,187,176,166,157,148,140,132,125,118
},
// Tuning -4
{
	881,832,785,741,699,660,623,588,555,524,494,467,
	441,416,392,370,350,330,312,294,278,262,247,233,
	220,208,196,185,175,165,156,147,139,131,123,117
},
// Tuning -3
{
	875,826,779,736,694,655,619,584,551,520,491,463,
	437,413,390,368,347,328,309,292,276,260,245,232,
	219,206,195,184,174,164,155,146,138,130,123,116
},
// Tuning -2
{
	868,820,774,730,689,651,614,580,547,516,487,460,
	434,410,387,365,345,325,307,290,274,258,244,230,
	217,205,193,183,172,163,154,145,137,129,122,115
},
// Tuning -1
{
	862,814,768,725,684,646,610,575,543,513,484,457,
	431,407,384,363,342,323,305,288,272,256,242,228,
	216,203,192,181,171,161,152,144,136,128,121,114
}
};

void CModPlayer_IRQ()
{
    CModPlayer::getInstance()->updateTick();

    OS_SetIrqCheckFlag(OS_IE_TIMER2);
    OS_StopTimer(OS_TIMER_2);
    CModPlayer::getInstance()->setTimer();
}

CModPlayer::CModPlayer()
{
	
}

BOOL CModPlayer::loadFile(CFile *f)
{
	int i = sizeof(TModHeader);
	int j = sizeof(TModSample);
	int k = sizeof(TModPattern);
	
	f->read(&mod_header, sizeof(TModHeader));

	f->read(mod_samples, sizeof(TModSample) * mod_header.mod_samples);

	f->read(mod_order, mod_header.mod_len);

	int nrp = mod_header.mod_channels * 64 * mod_header.mod_patterns;
	mod_patterns = new TModPattern[nrp];

	f->read(mod_patterns, nrp * sizeof(TModPattern));

	int smp = mod_header.mod_samples-1;
	u32 len = mod_samples[smp].sample_len*2 + mod_samples[smp].sample_offset;
	mod_sampleData = new s8[len];
	f->read(mod_sampleData, len);	

	return TRUE;
}
#define PCM_PLAY_CHANNEL1 4


void CModPlayer::play()
{
	initSong();
	setTimer();			
}

void CModPlayer::stop()
{
	OS_StopTimer(OS_TIMER_2);
	SND_StopTimer(0x0f,0,0,0);
}

void CModPlayer::setTimer()
{
	int freq = 50;
	
    OS_SetIrqFunction(OS_IE_TIMER2, CModPlayer_IRQ);
    (void)OS_EnableIrqMask(OS_IE_TIMER2);
    OS_StartTimer(OS_TIMER_2, 32728 / freq, OS_TIMER_PRESCALER_1024);
}

void CModPlayer::updateTick()
{
    while (SND_RecvCommandReply(SND_COMMAND_NOBLOCK) != NULL)
    {
    }

	m_tick++;
	if (m_tick >= m_speed)
	{
		updateRow();
		m_tick = 0;
		m_row ++;
		if (m_row >= 64)
		{
			m_row = 0;
			m_pattern ++;
			
			if (m_pattern >= mod_header.mod_len)
				initSong();
		}
	}
	else
	{
		updateEffect();
	}	

	SND_FlushCommand(SND_COMMAND_NOBLOCK);	
}

void CModPlayer::initSong()
{
	m_speed = 6;
	m_tick = m_speed;
	m_row = 0;
	m_pattern = 0;
	m_totalVolume = 7;
}

void CModPlayer::updateRow()
{
	int ch = mod_header.mod_channels;
	
	for (int i=0;i<ch; i++)
	{
		int ptrn = ch * 64 * mod_order[m_pattern] + ch * m_row + i;
		
		int sample = mod_patterns[ptrn].pat_sampleID;
		
		if (sample)
			playNote(sample-1, 7159090 / (amiga_table[0][mod_patterns[ptrn].pat_sampleNote] * 2), 64, i);
	}	
}

void CModPlayer::updateEffect()
{
}

void CModPlayer::playNote(u8 sample, u16 freq, u8 volume, u8 channel)
{
	int v = (volume * 2 * m_totalVolume)/10;
	if (volume > 127)
		volume = 127;
	
	SND_SetupChannelPcm(
		channel,					//channel
        SND_WAVE_FORMAT_PCM8,		//format
        &mod_sampleData[mod_samples[sample].sample_offset],				//data
        (mod_samples[sample].sample_repeatLen > 1)?SND_CHANNEL_LOOP_REPEAT:SND_CHANNEL_LOOP_1SHOT,		//loop
        mod_samples[sample].sample_repeatOffset/2,	//repeat offset
        mod_samples[sample].sample_len/2,	//len
        v, 						//volume
        SND_CHANNEL_DATASHIFT_NONE,	//shift
        SND_TIMER_CLOCK / freq,	//timer
        m_channelPan[channel]);						//pan
	

	SND_StartTimer(1 << channel, 0, 0, 0);
}

void CModPlayer::setVolume(u8 channel, u8 volume)
{
	int v = (volume * 2 * m_totalVolume)/10;
	if (volume > 127)
		volume = 127;

	
	SND_SetChannelVolume(1<<channel, v, SND_CHANNEL_DATASHIFT_NONE);
}

